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}
它应该可以工作。
我构建了一个自定义层,用于直接在模型内部重新缩放数据。这是必要的,因为我有一个单独的模型,它将通过链接多个模型来构建。这些模型中的每一个都有自己的缩放函数。在构建单个模型时,我在模型外部执行重新缩放,但是一旦层被链接,这就不再可能了。因此,它必须以建议的方式实施。
我创建了两个子分类层,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}
它应该可以工作。