实战tensorflow2.0自定义层次(以DenseLayer为例)

在本文中介绍两种自定义层次的方法:子类法与lambda方法,其中子类法适合用于定义参数较多的层次,而lambda方法更适合实现自定义一个没有参数的层次,例如:激活函数。相比于子类法,lambda方法实现起来更简单,代码量更少,下面进行具体介绍。

1、子类法定义DenseLayer(全连接层)

实现自定义DenseLayer与之前实现的wide_deep模型很相似,都是通过继承类的方式实现。只不过在wide_deep模型中是将初始化函数与build函数合在一块了,而在这里是分开的。

核心代码展示:

# customized dense layer.
class CustomizedDenseLayer(keras.layers.Layer):
    def __init__(self, units, activation=None, **kwargs):
        self.units = units #输出单元数
        self.activation = keras.layers.Activation(activation)
        super(CustomizedDenseLayer, self).__init__(**kwargs)
    
    def build(self, input_shape):
        """构建所需要的参数"""
        # x * w + b. x的input_shape:[None, a] ,output_shape: [None, b],w:[a,b]
        self.kernel = self.add_weight(name = 'kernel',
                                      shape = (input_shape[1], self.units),
                                      initializer = 'uniform', #初始化方法
                                      trainable = True)
        self.bias = self.add_weight(name = 'bias',
                                    shape = (self.units, ),
                                    initializer = 'zeros',
                                    trainable = True)
        super(CustomizedDenseLayer, self).build(input_shape)
    
    def call(self, x):
        """完成一次正向计算"""
        return self.activation(x @ self.kernel + self.bias)

model = keras.models.Sequential([
    CustomizedDenseLayer(30, activation='relu',
                         input_shape=x_train.shape[1:]),
    CustomizedDenseLayer(1),
])

note: keras.layers.Activation(activation)里小写的activation是一个函数(或者是字符串),然后传给keras.layers.Activation后构成了一个层次,在调用self.activation()的时候,这个会触发keras.layers.Activation的call方法,在call方法里,就是调用的之前传进去的activation方法去做。

 def call(self, inputs):
    return self.activation(inputs)

2、使用lambda方法自定义softplus激活函数层

softplus激活函数没有参数所以采用更简单的lambda方法实现。

核心代码展示:

# 激活函数:tf.nn.softplus : log(1+e^x)
customized_softplus = keras.layers.Lambda(lambda x : tf.nn.softplus(x))
#print(customized_softplus([-10., -5., 0., 5., 10.]))

可以看到在上面有一行注释了的用于测试softplus的代码。它的输出为:

tf.Tensor([4.5417706e-05 6.7153489e-03 6.9314718e-01 5.0067153e+00 1.0000046e+01], shape=(5,), dtype=float32)

即输入x,输出为log(1+e^x)

接下来把定义好的softplus层添加到刚刚定义的模型中,如下:

model = keras.models.Sequential([
    CustomizedDenseLayer(30, activation='relu',
                         input_shape=x_train.shape[1:]),
    CustomizedDenseLayer(1), #没有传activation,则默认activation为None,在构造函数中被赋值,在call函数中被使用
    customized_softplus,
    #keras.layers.Dense(1, activation = "softplus"),
    #keras.layers.Dense(1), keras.layers.Actication('softplus'),
])

note:其中:

 CustomizedDenseLayer(1),
 customized_softplus,

与  keras.layers.Dense(1, activation = "softplus"),

和  keras.layers.Dense(1),

     keras.layers.Actication('softplus'),

都是等价的。

附全部代码:

import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import sklearn
import pandas as pd
import os
import sys
import time
import tensorflow as tf

from tensorflow import keras

print(tf.__version__)
print(sys.version_info)
for module in mpl, np, pd, sklearn, tf, keras:
    print(module.__name__, module.__version__)

layer = tf.keras.layers.Dense(100)
layer = tf.keras.layers.Dense(100, input_shape=(None, 5))
layer(tf.zeros([10, 5]))

#layer的两个主要方法
layer.variables #打印出来layer里面包含的所有参数
# x * w + b
layer.trainable_variables#获得所有可训练的变量

from sklearn.datasets import fetch_california_housing

housing = fetch_california_housing()
print(housing.DESCR)
print(housing.data.shape)
print(housing.target.shape)

from sklearn.model_selection import train_test_split

x_train_all, x_test, y_train_all, y_test = train_test_split(
    housing.data, housing.target, random_state = 7)
x_train, x_valid, y_train, y_valid = train_test_split(
    x_train_all, y_train_all, random_state = 11)
print(x_train.shape, y_train.shape)
print(x_valid.shape, y_valid.shape)
print(x_test.shape, y_test.shape)

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)

# 激活函数:tf.nn.softplus : log(1+e^x)
customized_softplus = keras.layers.Lambda(lambda x : tf.nn.softplus(x))
#print(customized_softplus([-10., -5., 0., 5., 10.]))

# customized dense layer.
class CustomizedDenseLayer(keras.layers.Layer):
    def __init__(self, units, activation=None, **kwargs):
        self.units = units #输出单元数
        self.activation = keras.layers.Activation(activation)
        super(CustomizedDenseLayer, self).__init__(**kwargs)
    
    def build(self, input_shape):
        """构建所需要的参数"""
        # x * w + b. x的input_shape:[None, a] ,output_shape: [None, b],w:[a,b]
        self.kernel = self.add_weight(name = 'kernel',
                                      shape = (input_shape[1], self.units),
                                      initializer = 'uniform', #初始化方法
                                      trainable = True)
        self.bias = self.add_weight(name = 'bias',
                                    shape = (self.units, ),
                                    initializer = 'zeros',
                                    trainable = True)
        super(CustomizedDenseLayer, self).build(input_shape)
    
    def call(self, x):
        """完成一次正向计算"""
        return self.activation(x @ self.kernel + self.bias)

model = keras.models.Sequential([
    CustomizedDenseLayer(30, activation='relu',
                         input_shape=x_train.shape[1:]),
    CustomizedDenseLayer(1),
    customized_softplus,
    #keras.layers.Dense(1, activation = "softplus"),
    #keras.layers.Dense(1), keras.layers.Actication('softplus'),
])
model.summary()
model.compile(loss="mean_squared_error", optimizer="sgd")
callbacks = [keras.callbacks.EarlyStopping(
    patience=5, min_delta=1e-2)]

history = model.fit(x_train_scaled, y_train,
                    validation_data = (x_valid_scaled, y_valid),
                    epochs = 100,
                    callbacks = callbacks)

def plot_learning_curves(history):
    pd.DataFrame(history.history).plot(figsize=(8, 5))
    plt.grid(True)
    plt.gca().set_ylim(0, 1)
    plt.show()
plot_learning_curves(history)

model.evaluate(x_test_scaled, y_test, verbose=0)

原创文章 46 获赞 49 访问量 2190

猜你喜欢

转载自blog.csdn.net/qq_41660119/article/details/105790761