下面舉個例子說明自定義層的建構方法:
from
建構自定義層方法1: import tensorflow as tf
#自定義全連接配接層
class Linear(tf.keras.layers.Layer):
def __init__(self, units=1, input_dim=4):
super(Linear, self).__init__() #
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)
def call(self, inputs):
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)
可以發現這種方法裡面w和b是使用tf.Variable+w/b_init來定義的。
建構自定義層方法2: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)
可以發現這種方法裡面w和b是使用self.add_weight來定義的。
建構自定義層方法3: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)
self.b = self.add_weight(shape=(self.units,),
initializer='random_normal',
trainable=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)
可以發現這種方法裡面寫成了3個函數。
注意事項:
我們自定義一個名為MyDense的Layer:
import tensorflow as tf
#Dense
class MyDense(tf.keras.layers.Layer):
def __init__(self, units=32, **kwargs):
self.units = units
super(MyDense, self).__init__(**kwargs)
#build方法一般定義Layer需要被訓練的參數。
def build(self, input_shape):
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')
super(MyDense,self).build(input_shape) # 相當于設定self.built = True
#call方法一般定義正向傳播運算邏輯,__call__方法調用了它。
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
#如果要讓自定義的Layer通過Functional API 組合成模型時可以序列化,需要自定義get_config方法。
def get_config(self):
config = super(MyDense, self).get_config()
config.update({'units': self.units})
return config
inputs = tf.keras.Input(shape=(4,))
x = MyDense(units=16)(inputs)
x = tf.nn.tanh(x)
x = MyDense(units=3)(x) #0,1,2
# x= tf.keras.layers.Dense(16)(x)
predictions = tf.nn.softmax(x)
model = tf.keras.Model(inputs=inputs, outputs=predictions)
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])
#keras
model.fit(data, labels, batch_size=32, epochs=100,shuffle=True)
如果沒有在自定義層時候重寫get_config,那麼就會在儲存模型時候報錯:
model.save('keras_model_tf_version.h5')
_custom_objects = {
"MyDense" : MyDense,
}
new_model = tf.keras.models.load_model("keras_model_tf_version.h5",custom_objects=_custom_objects)
y_pred = new_model.predict(data)
解決方法:
_custom_objects = {
"MyDense" : MyDense,
}
最後,放上完整的案例代碼:
import tensorflow as tf
print(tf.__version__)
tf.test.is_gpu_available()
#Dense
class MyDense(tf.keras.layers.Layer):
def __init__(self, units=32, **kwargs):
self.units = units
super(MyDense, self).__init__(**kwargs)
#build方法一般定義Layer需要被訓練的參數。
def build(self, input_shape):
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')
super(MyDense,self).build(input_shape) # 相當于設定self.built = True
#call方法一般定義正向傳播運算邏輯,__call__方法調用了它。
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
#如果要讓自定義的Layer通過Functional API 組合成模型時可以序列化,需要自定義get_config方法。
def get_config(self):
config = super(MyDense, self).get_config()
config.update({'units': self.units})
return config
from sklearn import datasets
iris = datasets.load_iris()
data = iris.data
labels = iris.target
# from sklearn.preprocessing import MinMaxScaler
# data=MinMaxScaler().fit_transform(data)
#網絡 函數式建構的網絡
inputs = tf.keras.Input(shape=(4,))
x = MyDense(units=16)(inputs)
x = tf.nn.tanh(x)
x = MyDense(units=3)(x) #0,1,2
# x= tf.keras.layers.Dense(16)(x)
predictions = tf.nn.softmax(x)
model = tf.keras.Model(inputs=inputs, outputs=predictions)
data = np.concatenate((data,labels.reshape(150,1)),axis=-1)
np.random.shuffle(data)
labels = data[:,-1]
data = data[:,:4]
#優化器 Adam
#損失函數 交叉熵損失函數
#評估函數 #acc
model.compile(optimizer=tf.keras.optimizers.Adam(),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])
#keras
model.fit(data, labels, batch_size=32, epochs=100,shuffle=True)
model.summary()
model.save('keras_model_tf_version.h5')
_custom_objects = {
"MyDense" : MyDense,
}
new_model = tf.keras.models.load_model("keras_model_tf_version.h5",custom_objects=_custom_objects)
y_pred = new_model.predict(data)
np.argmax(y_pred,axis=1)