Tensorflow:自定义 TF 层不是 JSON 可序列化但已实现 get_config()

Tensorflow: Custom TF Layer Is not JSON Serializable but have get_config() implemented

我构建了一个自定义层,用于直接在模型内部重新缩放数据。这是必要的,因为我有一个单独的模型,它将通过链接多个模型来构建。这些模型中的每一个都有自己的缩放函数。在构建单个模型时,我在模型外部执行重新缩放,但是一旦层被链接,这就不再可能了。因此,它必须以建议的方式实施。

我创建了两个子分类层,FeatureMinMaxScaler()FeatureMinMaxDescaler()(如下所示),并且我在这两个层中实现了 get_config()

import numpy as np
import tensorflow as tf
import tensorflow.keras as krs
from sklearn.preprocessing import MinMaxScaler
from sys import exit

(x,y),(xtest,ytest) = tf.keras.datasets.boston_housing.load_data()
scaler = MinMaxScaler()
scaler2 = MinMaxScaler()
scaler.fit(x)
transformed = scaler.transform(x)

class FeatureMinMaxScaler( krs.layers.Layer ):
    def __init__(self, max_data, min_data, limits = (0.,1.) ):
        super(FeatureMinMaxScaler, self).__init__(trainable=False)
        # max_data = max_data.astype('float32')
        # min_data = min_data.astype('float32')
        self.max_data = tf.convert_to_tensor(max_data,dtype='float64')
        self.min_data = tf.convert_to_tensor(min_data,dtype='float64')
        self.limits = tf.convert_to_tensor(np.array(limits),dtype='float64')
        self.range = tf.constant(limits[1]-limits[0],dtype='float64')

        self.inv_denominator = tf.divide(tf.constant(1.,dtype='float64'), tf.subtract(self.max_data,self.min_data) )
        self.inv_denominator = tf.where(tf.math.is_inf(self.inv_denominator),tf.constant(0.,dtype='float64'),self.inv_denominator)

        self.scaling_multiplier = tf.multiply(self.inv_denominator,self.range)
        self.range_min = tf.constant(limits[0],dtype='float64')
        self.num_outputs = max_data.size


    def build(self, input_shape):
        pass

    def call(self, input):

        return tf.cast(tf.add( tf.multiply( tf.subtract(tf.cast(input,dtype='float64'), self.min_data), self.scaling_multiplier ), self.range_min ),dtype='float32')

    def get_config(self):
        data = {    'max_data': self.max_data,
                    'min_data': self.min_data,
                    'limits': self.limits,
                    'range': self.range,
                    'inv_denominator': self.inv_denominator,
                    'scaling_multiplier': self.scaling_multiplier,
                    'range_min': self.range_min,
                    'num_outputs': self.num_outputs}
        return data

class FeatureMinMaxDescaler( krs.layers.Layer ):
    def __init__(self, max_data, min_data, limits = (0.,1.) ):
        super(FeatureMinMaxDescaler, self).__init__(trainable=False)
        # max_data = max_data.astype('float32')
        # min_data = min_data.astype('float32')
        self.max_data = tf.convert_to_tensor(max_data,dtype='float64')
        self.min_data = tf.convert_to_tensor(min_data,dtype='float64')
        self.limits = tf.convert_to_tensor(np.array(limits),dtype='float64')
        self.range = tf.constant(limits[1]-limits[0],dtype='float64')

        self.inv_denominator = tf.divide(tf.constant(1.,dtype='float64'), self.range)

        self.scaling_multiplier = tf.multiply(self.inv_denominator,tf.subtract(self.max_data,self.min_data))
        self.range_min = tf.constant(limits[0],dtype='float64')
        self.num_outputs = max_data.size


    def build(self, input_shape):
        pass

    def call(self, input):
        return tf.cast(tf.add( tf.multiply( tf.subtract(tf.cast(input,dtype='float64'), self.range_min), self.scaling_multiplier ), self.min_data ),dtype='float32')

    def get_config(self):
        data = {    'max_data': self.max_data,
                    'min_data': self.min_data,
                    'limits': self.limits,
                    'range': self.range,
                    'inv_denominator': self.inv_denominator,
                    'scaling_multiplier': self.scaling_multiplier,
                    'range_min': self.range_min,
                    'num_outputs': self.num_outputs}
        return data

inputs = krs.Input(shape=(x.shape[1],))
outputs = FeatureMinMaxScaler(scaler.data_max_, scaler.data_min_)(inputs)

model = krs.models.Model(inputs = inputs, outputs = outputs )

model.compile(optimizer='adam')

krs.models.save_model(model,"./serialization_test.mdl")

但是,当我尝试保存使用这些缩放层的模型时,我收到此错误

TypeError: ('Not JSON Serializable:', <tf.Tensor: shape=(13,), dtype=float64, numpy=
array([ 88.9762, 100.    ,  27.74  ,   1.    ,   0.871 ,   8.725 ,
       100.    ,  10.7103,  24.    , 711.    ,  22.    , 396.9   ,
        37.97  ])>)

是什么导致了这个问题?我该如何解决?

Tensorflow 张量不可 json 序列化。您只需要在从 get_config() 方法返回的字典中使用原始数据类型。

另外,你不需要保存所有的成员变量,只需要重新创建层所需的值就足够了。因此,在您的情况下 max_data、min_data,限制就足够了。而且看起来你不需要这些是张量。因此,在构造函数中按如下方式设置这 3 个变量。

        self.max_data = max_data
        self.min_data = min_data
        self.limits = limits

并在

    def get_config(self):
        data = {    'max_data': self.max_data,
                    'min_data': self.min_data,
                    'limits': self.limits}

它应该可以工作。